<?php
/**
 * @link https://www.kancloud.cn/cleverstone/ymb2
 * @copyright Copyright (c) 2020 Yii Manager Software LLC
 */

namespace builder\tab;

use Yii;
use yii\web\AssetBundle;
use yii\web\View;
use yii\base\InvalidArgumentException;
use builder\base\Builder;
use builder\helper\H5;
use builder\helper\RegEx;
use builder\base\ViewBuilderInterface;
use builder\helper\App;
use builder\tab\util\titem\TabItemType;

/**
 * 选项卡构建器
 * @property bool $partial 是否局部继承
 * @property string $title 页标题
 * @property array $rootLayout 选项卡根布局
 * @property string $theme 选项卡风格
 * @property array $tabItem 选项卡内容项
 * @property array $extraJs 额外的JS
 * @property array $extraCss 额外的CSS
 * @property array $extraAssetBundle 额外的静态包
 * @author cleverstone
 * @since ym2.0
 */
class TabBuilder extends Builder implements ViewBuilderInterface
{
    // 头部切点
    const POS_HEAD = 0x01;

    // 尾部切点
    const POS_END = 0x02;

    /**
     * @var array 切点
     * @see registerPointcut()
     * @see beginPage()
     * @see endPage()
     */
    private $_pointcutBody = [];

    /**
     * @var string 标题
     * @see $title
     * @see setTitle()
     * @see getTitle()
     */
    private $_title = '';

    /**
     * @var array 根布局
     * @see $rootLayout
     * @see setRootLayout()
     * @see getRootLayout()
     */
    private $_rootLayout = [];

    /**
     * @var string 风格
     * - brief 简约风
     * - card  卡片风
     *
     * @see $theme
     * @see setTheme()
     * @see getTheme()
     */
    private $_theme = '';

    /**
     * @var array 选项卡内容项
     * 支持的key(类型string)有:
     * - text 普通文本
     * - html 超文本
     *
     * 支持的value(类型array)有:
     * - id string 项ID
     * - content string 项内容
     * - selected boolean 是否选中项
     * - switchProperty string js切换重载属性,即: window.ym2BehaviorReqExport对象下的方法名
     *
     * @see $tabItem
     * @see setTabItem()
     * @see getTabItem()
     */
    private $_tabItem = [];

    /**
     * @var bool 是否局部继承
     * @see $partial
     * @see setPartial()
     * @see getPartial()
     */
    private $_partial = false;

    /**
     * @var array 额外的JS
     * ```php
     * $table->extraCss = <<<JS
     * console.log("测试一下 [setExtraCss] 方法;")
     * JS;
     *
     * ```
     * @see $extraJs
     * @see setExtraJs()
     * @see getExtraJs()
     */
    private $_extraJs = [];

    /**
     * @var array 额外的CSS
     * ```php
     * $table->extraCss = <<<CSS
     * body{background-color: #fff;}
     * CSS;
     *
     * ```
     * @see $extraCss
     * @see setExtraCss()
     * @see getExtraCss()
     */
    private $_extraCss = [];

    /**
     * @var array 额外的静态资源包
     * ```php
     * $table->extraAssetBundle = MemberAsset::class;
     *
     * ```
     * @see $extraAssetBundle
     * @see setExtraAssetBundle()
     * @see getExtraAssetBundle()
     */
    private $_extraAssetBundle = [];

    /**
     * 实例化
     * @param array $config
     * @return TabBuilder
     */
    public static function instance($config = [])
    {
        return new static($config);
    }

    /**
     * 注册切点
     * @param string $content 注册的内容
     * @param int $pos 切点标记
     * @return $this
     */
    public function registerPointcut($content, $pos = self::POS_HEAD)
    {
        $this->_pointcutBody[$pos][] = $content;
        return $this;
    }

    /**
     * 页面头部位置
     * @return null|string
     */
    public function beginPage()
    {
        if (empty($this->_pointcutBody[self::POS_HEAD])) {
            return null;
        }

        return implode("\n", $this->_pointcutBody[self::POS_HEAD]);
    }

    /**
     * 页面尾部位置
     * @return null|string
     */
    public function endPage()
    {
        if (empty($this->_pointcutBody[self::POS_END])) {
            return null;
        }

        return implode("\n", $this->_pointcutBody[self::POS_END]);
    }

    /**
     * 设置标题
     * @param string $title
     * @return $this
     */
    public function setTitle($title)
    {
        $this->_title = (string)$title;
        return $this;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->_title;
    }

    /**
     * 设置根布局
     * @param array $options
     * @return $this
     */
    public function setRootLayout(array $options)
    {
        if (!empty($options['class'])) {
            $this->formatUiClass($options['class']);
        } else {
            $options['class'] = '';
        }

        if (!empty($options['style'])) {
            $this->formatStyle($options['style']);
        } else {
            $options['style'] = '';
        }

        if (!empty($options['attribute'])) {
            $this->formatHtmlAttribute($options['attribute']);
        } else {
            $options['attribute'] = '';
        }

        $this->_rootLayout = $options;
        return $this;
    }

    /**
     * @return array
     */
    public function getRootLayout()
    {
        if (empty($this->_rootLayout)) {
            return [
                'style' => '',
                'class' => '',
                'attribute' => '',
            ];
        }

        return $this->_rootLayout;
    }

    /**
     * 设置选项卡风格
     * @param string $theme
     * @return $this
     */
    public function setTheme($theme = 'brief')
    {
        if (in_array($theme, ['brief', 'card', 'column'])) {
            $this->_theme = "layui-tabs-$theme";
        }

        return $this;
    }

    /**
     * @return string
     */
    public function getTheme()
    {
        return $this->_theme;
    }

    /**
     * 设置选项卡内容项
     * @param array $tabItem 项值支持注入。
     * @return $this
     */
    public function setTabItem(array $tabItem)
    {
        foreach ($tabItem as &$item) {
            if (is_callable($item)) {
                $item = Yii::createObject($item);
            }

            if ($item instanceof TabItemType) {
                $item = $item->_toArray();
            }

            empty($item['selected']) && $item['selected'] = false;
        }

        $this->_tabItem = $tabItem;
        return $this;
    }

    /**
     * @return array
     * @throws \yii\base\InvalidConfigException
     */
    public function getTabItem()
    {
        $tabItem = $this->_tabItem;
        if (empty($tabItem)) {
            return [];
        }

        $tabLabel = [];
        $tabContent = [];
        foreach ($tabItem as $label => $item) {
            $tabLabel[] = [
                'id' => $item['id'],
                'label' => $label,
                'selected' => $item['selected'] ? 'layui-this' : '',
            ];

            $tabContent[] = [
                'id' => $item['id'],
                'content' => $item['content'],
                'selected' => $item['selected'] ? 'layui-show' : '',
            ];
        }

        return [
            'tabLabel' => $tabLabel,
            'tabContent' => $tabContent,
        ];
    }

    /**
     * 设置视图局部继承
     * @param bool $boolean
     * @return $this
     */
    public function setPartial($boolean = true)
    {
        $this->_partial = $boolean;
        return $this;
    }

    /**
     * @return bool
     */
    public function getPartial()
    {
        return $this->_partial;
    }

    /**
     * 设置额外的JS
     * @param array|string $js 额外的JS脚本
     * @return $this
     */
    public function setExtraJs($js)
    {
        $js = (array)$js;
        foreach ($js as &$value) {
            if (is_callable($value)) {
                $value = call_user_func($value);
            }
        }

        $this->_extraJs = array_merge($this->_extraJs, $js);
        return $this;
    }

    /**
     * 获取额外的JS
     * @return array
     */
    public function getExtraJs()
    {
        return $this->_extraJs;
    }

    /**
     * 设置额外的CSS
     * @param array|string $css 额外的CSS脚本
     * @return $this
     */
    public function setExtraCss($css)
    {
        $css = (array)$css;
        foreach ($css as &$value) {
            if (is_callable($value)) {
                $value = call_user_func($value);
            }
        }

        $this->_extraCss = array_merge($this->_extraCss, $css);
        return $this;
    }

    /**
     * 获取额外的CSS
     * @return array
     */
    public function getExtraCss()
    {
        return $this->_extraCss;
    }

    /**
     * 设置额外的静态资源包
     * @param string|array $extraAssetBundle 静态资源包
     * @return $this
     */
    public function setExtraAssetBundle($extraAssetBundle)
    {
        $extraAssetBundle = (array)$extraAssetBundle;

        // 检查
        foreach ($extraAssetBundle as $assetBundle) {
            $tempObj = new $assetBundle;
            if (!$tempObj instanceof AssetBundle) {
                throw new InvalidArgumentException($assetBundle . ' is not instance of ' . AssetBundle::class);
            }
        }

        $this->_extraAssetBundle = array_merge($this->_extraAssetBundle, $extraAssetBundle);
        return $this;
    }

    /**
     * 获取额外的静态资源包
     * @return array
     */
    public function getExtraAssetBundle()
    {
        return $this->_extraAssetBundle;
    }

    /**
     * 构建器名称
     * @return string
     */
    public function getName()
    {
        return 'tab';
    }

    /**
     * @return string the view path that may be prefixed to a relative view name.
     */
    public function getViewPath()
    {
        return __DIR__;
    }

    /**
     * 选项卡渲染
     * @param boolean $onlyRenderContent 是否仅渲染内容
     * @return string
     * @throws \yii\base\InvalidConfigException
     */
    public function render($onlyRenderContent = false)
    {
        $content = $this->_renderHtml();

        // 仅内容渲染
        if ($onlyRenderContent) {
            return $content;
        }

        // 局部布局渲染(不包含: 菜单和导航栏)
        if ($this->partial) {
            return $this->_view->renderFile($this->partialPath, ['content' => $content], $this);
        }

        // 主布局渲染(包含: 菜单和导航栏)
        return $this->_view->renderFile($this->mainPath, ['content' => $content], $this);
    }

    /**
     * 渲染HTML
     * @return string
     * @throws \yii\base\InvalidConfigException
     */
    private function _renderHtml()
    {
        if ($this->title) {
            // 注册页标题
            $this->_view->title = H5::encode(App::params('admin.brandName') . ' | ' . $this->title);
        }

        // 注册JS脚本
        $this->_view->registerJs($this->_resolveJsScript(), View::POS_END);

        // 注册额外CSS脚本
        if (!empty($this->extraCss)) {
            $this->_view->registerCss(implode("\n", $this->extraCss));
        }

        // 注册额外的AssetBundle
        if (!empty($this->extraAssetBundle)) {
            foreach ($this->extraAssetBundle as $assetBundle) {
                $this->_view->registerAssetBundle($assetBundle);
            }
        }

        $content = $this->_view->render('view', [
            // view.php中参数注册
            'theme' => $this->theme,                // 风格
            'tabItem' => $this->tabItem,            // 项(已格式化)
            'rootLayout' => $this->rootLayout,      // 根布局

        ], $this);

        return $content;
    }

    /**
     * 解析选项卡组件的JS脚本
     * @return string
     */
    private function _resolveJsScript()
    {
        $jsScripts = $this->_view->render('app', [
            // app.php中参数注册
            'tabItem' => $this->_tabItem,        // 项(未格式化)
            'extraJs' => $this->extraJs,         // 额外的JS脚本

        ], $this);

        return RegEx::js($jsScripts);
    }
}